//
//  ViewController.m
//  Runtime
//
//  Created by allin on 2021/7/14.
//

#import "ViewController.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import <dlfcn.h> /// 动态链接库头文件
#import <mach-o/ldsyms.h> ///内核动态系统库头文件

#import "Persion.h"
#import "NSObject+Helper.h"

@interface ViewController ()<UITableViewDelegate>
{
    NSString *_runtime1;
    __weak id _lgID;
    
}
@property (nonatomic ,copy) NSString *logic;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    Persion *p = Persion.new;
    //消息转发一、在类及父类 的 cache和method_list中找
    [p eat];
    [Persion performSelector:@selector(help)];
    //消息转发二、动态增加方法
    NSLog(@"实例方法");
    [p eat1];
    NSLog(@"类方法");
    [Persion eat1];
}


#pragma mark - 解除IMP与Block关联
- (void)lg_imp_removeBlock {
    //参数:IMP
    //返回:BOOL
    BOOL result = imp_removeBlock(class_getMethodImplementation(self.class, NSSelectorFromString(@"lg_method")));
    NSLog(@"lg_imp_removeBlock:%d",result);
}

#pragma mark - 通过IMP获取Block
- (void)lg_imp_getBlock {
    void (^blcok) (NSString *) = ^(NSString *str) {
        NSLog(@"lg_imp_implementationWithBlock:%@",str);
    };
    //参数:IMP
    //返回:block
    void (^result) (NSString *) = imp_getBlock(imp_implementationWithBlock(blcok));
    result(@"hello word");
}

#pragma mark - 通过block获取一个方法的实现
- (void)lg_imp_implementationWithBlock {
    void (^blcok) (NSString *) = ^(NSString *str) {
        NSLog(@"lg_imp_implementationWithBlock");
    };
    //参数:block
    //返回:IMP
    IMP result = imp_implementationWithBlock(blcok);
    result();
}

#pragma mark - 设置突变处理函数
- (void)lg_objc_setEnumerationMutationHandler {
    //参数:函数指针
    objc_setEnumerationMutationHandler(enumerationMutationHandler);
}
void enumerationMutationHandler(id obj) {
    NSLog(@"enumerationMutationHandler");
}

#pragma mark - 检测到突变时,编译器将插入次函数 并且调用objc_setEnumerationMutationHandler设置的回调函数,如果没有设置,则会崩溃
- (void)lg_objc_enumerationMutation {
    //参数:id
    objc_enumerationMutation(self);
}

#pragma mark - 获取属性的属性列表
- (void)lg_property_copyAttributeList {
    objc_property_t t = class_getProperty(self.class, [@"logic" UTF8String]);
    unsigned int count = 0;
    //参数:1.objc_property_t 2.unsigned int *
    //返回:属性的属性列表
    objc_property_attribute_t *result = property_copyAttributeList(t, &count);
    for (int i = 0; i < count; i ++) {
        objc_property_attribute_t t = result[i];
        NSLog(@"lg_property_copyAttributeList:%@",[NSString stringWithUTF8String:t.name]);
    }
    free(result);
}

#pragma mark - 获取属性的指定属性的值
- (void)lg_property_copyAttributeValue {
    objc_property_t t = class_getProperty(self.class, [@"logic" UTF8String]);
    //参数:1.objc_property_t 2.属性的属性
    //返回:属性的属性的值
    char *result = property_copyAttributeValue(t, [@"T" UTF8String]);
    NSLog(@"lg_property_copyAttributeValue:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 获取属性的属性
- (void)lg_property_getAttributes {
    objc_property_t t = class_getProperty(self.class, [@"logic" UTF8String]);
    //参数:objc_property_t
    //返回:属性的属性
    const char *result = property_getAttributes(t);
    NSLog(@"lg_property_getAttributes:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 获取属性的名称
- (void)lg_property_getName {
    objc_property_t t = class_getProperty(self.class, [@"logic" UTF8String]);
    //参数:objc_property_t
    //返回:属性的名称
    const char *result = property_getName(t);
    NSLog(@"lg_property_getName:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 判断一个协议是否遵循另一个协议
- (void)lg_protocol_conformsToProtocol {
    Protocol *pro1 = objc_getProtocol([@"UITableViewDelegate" UTF8String]);
    Protocol *pro2 = objc_getProtocol([@"UIScrollViewDelegate" UTF8String]);
    //参数:Protocol
    //返回:BOOL
    BOOL result = protocol_conformsToProtocol(pro1, pro2);
    NSLog(@"lg_protocol_conformsToProtocol:%d",result);
}

#pragma mark - 获取协议中采用的协议列表
- (void)lg_protocol_copyProtocolList {
    Protocol *pro = objc_getProtocol([@"UITableViewDelegate" UTF8String]);
    unsigned int count = 0;
    //参数:1.Protocol 2.unsigned int *
    //返回:协议列表
    Protocol __unsafe_unretained **result = protocol_copyProtocolList(pro, &count);
    for (int i = 0; i < count; i ++) {
        Protocol *p = result[i];
        NSLog(@"lg_protocol_copyProtocolList:%@",p);
    }
    free(result);
}

#pragma mark - 获取协议中指定的属性
- (void)lg_protocol_getProperty {
    Protocol *pro = objc_getProtocol([@"UITableViewDelegate" UTF8String]);
    //参数:1.Protocol 2.属性名称 3.是否为必须方法 4.是否为实例方法
    objc_property_t result = protocol_getProperty(pro, [@"" UTF8String], YES, YES);
    NSLog(@"lg_protocol_getProperty:%p",result);
}

#pragma mark - 获取协议的属性列表
- (void)lg_protocol_copyPropertyList {
    Protocol *pro = objc_getProtocol([@"UITableViewDelegate" UTF8String]);
    unsigned int count = 0;
    //参数:1.Protocol 2.unsigned int *
    //返回:协议的属性列表
    objc_property_t *result = protocol_copyPropertyList(pro, &count);
    for (int i = 0; i < count; i ++) {
        objc_property_t t = result[i];
        NSLog(@"lg_protocol_copyPropertyList:%p",t);
        
    }
}

#pragma mark - 获取协议中指定方法的描述结构体
- (void)lg_protocol_getMethodDescription {
    Protocol *pro = objc_getProtocol([@"UITableViewDelegate" UTF8String]);
    //参数:1.Protocol 2.SEL 3.是否为必须方法 4.是否为实例方法
    struct objc_method_description result = protocol_getMethodDescription(pro, NSSelectorFromString(@"tableView:willDisplayCell:forRowAtIndexPath:"), NO, YES);
    NSLog(@"lg_protocol_getMethodDescription:%p",result.name);
}

#pragma mark - 获取满足条件的协议的方法列表
- (void)lg_protocol_copyMethodDescriptionList {
    Protocol *pro = objc_getProtocol([@"UITableViewDelegate" UTF8String]);
    unsigned int count = 0;
    //参数:1.Protocol 2.是否为必须方法 3.是否为实例方法 4.unsigned int *
    struct objc_method_description *result = protocol_copyMethodDescriptionList(pro, NO, YES, &count);
    for (int i = 0; i < count; i ++) {
        struct objc_method_description des = result[i];
        NSLog(@"lg_protocol_copyMethodDescriptionList:%p",des.name);
    }
}

#pragma mark - 判断俩个协议是否相等
- (void)lg_protocol_isEqual {
    Protocol *pro1 = objc_getProtocol([@"UITableViewDelegate" UTF8String]);
    Protocol *pro2 = objc_getProtocol([@"UITableViewDataSource" UTF8String]);
    //参数:Protocol
    //返回:BOOL
    BOOL result = protocol_isEqual(pro1, pro2);
    NSLog(@"lg_protocol_isEqual:%d",result);
}

#pragma mark - 获取协议的名称
- (void)lg_protocol_getName {
    Protocol *pro = objc_getProtocol([@"UITableViewDelegate" UTF8String]);
    //参数:协议Protocol
    //返回:协议名称
    const char *result = protocol_getName(pro);
    NSLog(@"lg_protocol_getName:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 向协议中添加属性
- (void)lg_protocol_addProperty {
    Protocol *pro = objc_allocateProtocol([@"LGProtocol" UTF8String]);
    objc_property_attribute_t type = { "T", "@\"NSString\"" };
    objc_property_attribute_t ownership = { "C", "" }; // C = copy
    objc_property_attribute_t backingivar  = { "V", "_logic" };
    objc_property_attribute_t attrs[] = { type, ownership, backingivar };
    //参数:1.协议Protocol 2.属性的名称 3.属性的属性 4.属性的属性的个数 5.是否为协议的必须方法 6.填YES
    protocol_addProperty(pro, [@"logic" UTF8String], attrs, 3, YES, YES);
}

#pragma mark - 向协议中添加协议
- (void)lg_protocol_addProtocol {
    Protocol *pro1 = objc_getProtocol([@"UITableViewDelegate" UTF8String]);
    Protocol *pro2 = objc_allocateProtocol([@"LGProtocol" UTF8String]);
    //参数:1.要添加到的协议 2.要添加的协议
    protocol_addProtocol(pro1, pro2);
}

#pragma mark - 向协议添加方法
- (void)lg_protocol_addMethodDescription {
    Protocol *pro = objc_getProtocol([@"UITableViewDelegate" UTF8String]);
    //参数:1.协议Protocol 2.SEL 3.方法名称 4.是否为协议必须方法 5.是否为实例方法
    protocol_addMethodDescription(pro, NSSelectorFromString(@"lg_method"), [@"lgProtocolMethod" UTF8String], YES, YES);
}

#pragma mark - 注册协议
- (void)lg_objc_registerProtocol {
    Protocol *result = objc_allocateProtocol([@"LGProtocol" UTF8String]);
    //参数:协议Protocol
    objc_registerProtocol(result);
}

#pragma mark - 创建协议
- (void)lg_objc_allocateProtocol {
    //参数:协议的名称
    //返回:协议
    Protocol *result = objc_allocateProtocol([@"LGProtocol" UTF8String]);
    NSLog(@"lg_objc_allocateProtocol:%@",result);
}

#pragma mark - 获取所有的协议列表
- (void)lg_objc_copyProtocolList {
    unsigned int count = 0;
    //参数:unsigned int *
    //返回:所有的协议列表
    Protocol __unsafe_unretained **result = objc_copyProtocolList(&count);
    for (int i = 0; i < count; i ++) {
        Protocol *pro = result[i];
        NSLog(@"lg_objc_copyProtocolList:%@",pro);
    }
}

#pragma mark - 获取指定的协议
- (void)lg_objc_getProtocol {
    //参数:协议名称
    //返回:协议
    Protocol *result = objc_getProtocol([@"UITableViewDelegate" UTF8String]);
    NSLog(@"lg_objc_getProtocol:%@",result);
}

#pragma mark - 判断俩个选择器是否相等
- (void)lg_sel_isEqual {
    SEL sel1 = NSSelectorFromString(@"lg_method1");
    SEL sel2 = NSSelectorFromString(@"lg_method2");
    //参数:SEL
    //返回:BOOL
    BOOL result = sel_isEqual(sel1, sel2);
    NSLog(@"lg_sel_isEqual:%d",result);
}

#pragma mark - 注册方法
- (void)lg_sel_getUid {
    //参数:const char *
    //返回:SEL
    SEL result = sel_getUid([@"lglglg" UTF8String]);
    NSLog(@"sel_getUid:%p",result);
}

#pragma mark - 注册方法
- (void)lg_sel_registerName {
    //参数:const char *
    //返回:SEL
    SEL result = sel_registerName([@"lglglg" UTF8String]);
    NSLog(@"lg_sel_registerName:%p",result);
}

#pragma mark - 获取方法的名称
- (void)lg_sel_getName {
    SEL sel = NSSelectorFromString(@"lg_method");
    //参数:SEL
    //返回:方法的名称
    const char *result = sel_getName(sel);
    NSLog(@"lg_sel_getName:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 获取指定库或框架中的所有类的名称
- (void)lg_objc_copyClassNamesForImage {
    unsigned int outCount = 0;
    Dl_info info;
    dladdr(&_mh_execute_header, &info);
    //参数:1.库或者框架 2.unsigned int *
    //返回:指定库或框架中的所有类的名称
    const char **result = objc_copyClassNamesForImage(info.dli_fname, &outCount);
    for (int i = 0; i < outCount; i ++) {
        const char *c = result[i];
        NSLog(@"lg_objc_copyClassNamesForImage:%@",[NSString stringWithUTF8String:c]);
    }
}

#pragma mark - 获取类源自的动态库的名称
- (void)lg_class_getImageName {
    //参数:类Class
    //返回:源自的动态库的名称
    const char *result = class_getImageName(self.class);
    NSLog(@"lg_class_getImageName:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 获取所有的objc框架和动态库
- (void)lg_objc_copyImageNames {
    unsigned int a = 0;
    //参数:unsigned int *
    //返回:C字符串数组
    const char **result = objc_copyImageNames(&a);
    for (int i = 0; i < a; i ++) {
        const char *c = result[i];
        NSLog(@"lg_objc_copyImageNames:%@",[NSString stringWithUTF8String:c]);
    }
}

#pragma mark - 交换俩种方法的实现
- (void)lg_method_exchangeImplementations {
    Method method1 = class_getInstanceMethod(self.class, @selector(lg_method1));
    Method method2 = class_getInstanceMethod(self.class, @selector(lg_method2));
    //参数:Method
    method_exchangeImplementations(method1, method2);
    [self lg_method1];
    [self lg_method2];
}

#pragma mark - 设置方法的实现
- (void)lg_method_setImplementation {
    Method method = class_getInstanceMethod(self.class, @selector(lg_method));
    IMP imp = class_getMethodImplementation(self.class, @selector(lg_method1));
    //参数:1.Method 2.IMP
    //返回:方法的先前实现
    IMP result = method_setImplementation(method, imp);
    NSLog(@"lg_method_setImplementation:%p",result);
    result();
    [self lg_method];
}

#pragma mark - 获取方法的结构体
- (void)lg_method_getDescription {
    Method method = class_getInstanceMethod(self.class, @selector(lg_method));
    //参数:Method
    //返回:方法的结构体
    struct objc_method_description *result = method_getDescription(method);
    NSLog(@"lg_method_getDescription:%p",result);
}

#pragma mark - 获取单个参数的类型
- (void)lg_method_getArgumentType {
    Method method = class_getInstanceMethod(self.class, @selector(lg_method));
    char result[10];
    //参数:1.Method 2.参数索引 3.char数组 4.char数组的长度
    method_getArgumentType(method, 0, result, sizeof(result));
    NSLog(@"lg_method_getArgumentType:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 获取方法参数的数量
- (void)lg_method_getNumberOfArguments {
    Method method = class_getInstanceMethod(self.class, @selector(lg_method));
    //参数:Method
    //返回:参数的个数
    unsigned int result = method_getNumberOfArguments(method);
    NSLog(@"lg_method_getNumberOfArguments:%d",result);
}

#pragma mark - 获取方法的返回值类型
- (void)lg_method_getReturnType {
    Method method = class_getInstanceMethod(self.class, @selector(lg_method));
    //参数:1.Method 2.char数组 3.char数组的长度
    char result[10];
    method_getReturnType(method,result,sizeof(result));
    NSLog(@"lg_method_getReturnType:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 获取方法的单个参数类型
- (void)lg_method_copyArgumentType {
    Method method = class_getInstanceMethod(self.class, @selector(lg_method));
    //参数:1.Method 2.unsigned int参数索引
    //返回:参数类型
    char *result = method_copyArgumentType(method, 0);
    NSLog(@"lg_method_copyReturnType:%@",[NSString stringWithUTF8String:result]);
    free(result);
}

#pragma mark - 获取方法的返回值类型
- (void)lg_method_copyReturnType {
    Method method = class_getInstanceMethod(self.class, @selector(lg_method));
    //参数:Method
    //返回:方法的返回值类型
    char *result = method_copyReturnType(method);
    NSLog(@"lg_method_copyReturnType:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 获取描述方法的参数和返回值类型的字符串
- (void)lg_method_getTypeEncoding {
    Method method = class_getInstanceMethod(self.class, @selector(lg_method));
    //参数:Method
    //返回:描述方法的参数和返回值类型的字符串
    const char *result = method_getTypeEncoding(method);
    NSLog(@"lg_method_getTypeEncoding:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 获取方法的实现
- (void)lg_method_getImplementation {
    Method method = class_getInstanceMethod(self.class, @selector(lg_method));
    //参数:Mothod
    //返回:IMP指针
    IMP result = method_getImplementation(method);
    NSLog(@"lg_method_getImplementation:%p",result);
}

#pragma mark - 获取方法名称
- (void)lg_method_getName {
    Method method = class_getInstanceMethod(self.class, @selector(lg_method));
    //参数:Mothod
    //返回:SEL指针
    SEL result = method_getName(method);
    NSLog(@"lg_method_getName:%p",result);
}

#pragma mark - 删除关联
- (void)lg_objc_removeAssociatedObjects {
    //参数:关联的对象
    objc_removeAssociatedObjects(self);
}
#pragma mark - 获取关联的值
- (void)lg_objc_getAssociatedObject {
    //参数:1.关联的对象 2.key
    //返回:关联的值
    id result = objc_getAssociatedObject(self, [@"LGKey" UTF8String]);
    NSLog(@"lg_objc_getAssociatedObject:%@",result);
}
#pragma mark - 设置关联
- (void)lg_objc_setAssociatedObject {
    /**
     policy：关联策略。有五种关联策略。
     OBJC_ASSOCIATION_ASSIGN 等价于 @property(assign)。
     OBJC_ASSOCIATION_RETAIN_NONATOMIC等价于 @property(strong, nonatomic)。
     OBJC_ASSOCIATION_COPY_NONATOMIC等价于@property(copy, nonatomic)。
     OBJC_ASSOCIATION_RETAIN等价于@property(strong,atomic)。
     OBJC_ASSOCIATION_COPY等价于@property(copy, atomic)。
    */
    //参数:1.要关联的对象 2.全局唯一KEY 3.关联的obj 4.关联策略policy
    objc_setAssociatedObject(self, [@"LGKey" UTF8String], @"123456", OBJC_ASSOCIATION_COPY_NONATOMIC);
}

#pragma mark - 获取实例变量的偏移量
- (void)lg_ivar_getOffset {
    Ivar ivar = class_getInstanceVariable(self.class, [@"_logic" UTF8String]);
    //参数:Ivar
    //返回:实例变量的类型
    ptrdiff_t result = ivar_getOffset(ivar);
    NSLog(@"lg_ivar_getOffset:%td",result);
}

#pragma mark - 获取实例变量的类型
- (void)lg_ivar_getTypeEncoding {
    Ivar ivar = class_getInstanceVariable(self.class, [@"_logic" UTF8String]);
    //参数:Ivar
    //返回:实例变量的类型
    const char *result = ivar_getTypeEncoding(ivar);
    NSLog(@"lg_ivar_getTypeEncoding:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 获取实例变量名称
- (void)lg_ivar_getName {
    Ivar ivar = class_getInstanceVariable(self.class, [@"_logic" UTF8String]);
    //参数:Ivar
    //返回:实例变量的名称
    const char *result = ivar_getName(ivar);
    NSLog(@"lg_ivar_getName:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 获取指定类的元类定义
- (void)lg_objc_getMetaClass {
    //参数:类的名称
    //返回:类Class
    id result = objc_getMetaClass([@"ViewController" UTF8String]);
    NSLog(@"objc_getMetaClass:%@",result);
}

#pragma mark - 获取指定类的类定义
- (void)lg_objc_getRequiredClass {
    //参数:类的名称
    //返回:类Class
    Class result = objc_getRequiredClass([@"ViewController" UTF8String]);
    NSLog(@"lg_objc_getRequiredClass:%@",result);
}

#pragma mark - 获取指定类的类定义
- (void)lg_objc_getClass {
    //参数:类的名称
    //返回:类Class
    Class result = objc_getClass([@"ViewController" UTF8String]);
    NSLog(@"lg_objc_getClass:%@",result);
}

#pragma mark - 获取指定类的类定义
- (void)lg_objc_lookUpClass {
    //参数:类的名称
    //返回:类Class
    Class result = objc_lookUpClass([@"ViewController" UTF8String]);
    NSLog(@"lg_objc_lookUpClass:%@",result);
}

#pragma mark - 获取已注册的类
- (void)lg_objc_copyClassList {
    unsigned int outCount;
    //参数:整数指针
    //返回:已注册的类的指针列表
    Class *result = objc_copyClassList(&outCount);
    for (int i = 0; i < outCount; i++) {
        NSLog(@"lg_objc_copyClassList:%s", class_getName(result[i]));
    }
    free(result);
}

#pragma mark - 获取已注册的类的数量
- (void)lg_objc_getClassList {
    //参数:1.传NUll获取当前注册的所有类 2.传0
    //返回:所有注册类的总数
    int result = objc_getClassList(NULL, 0);
    NSLog(@"lg_objc_getClassList:%d",result);
}

#pragma mark - 设置对象的类
- (void)lg_object_setClass {
    //参数:1.对象obj 2.类Class
    //返回:类Class
    Class result = object_setClass(self, [UIViewController class]);
    NSLog(@"lg_object_setClass:%@",result);
}

#pragma mark - 获取对象的类对象
- (void)lg_object_getClass {
    //参数:对象obj
    //返回:类Class
    Class result = object_getClass(self);
    NSLog(@"lg_object_getClass:%@",result);
}

#pragma mark - 获取对象的类名
- (void)lg_object_getClassName {
    //参数:对象obj
    //返回:对象的类名
    const char*result = object_getClassName(self);
    NSLog(@"lg_object_getClassName:%@",[NSString stringWithUTF8String:result]);
}

#pragma mark - 设置对象中实例变量的值
- (void)lg_object_setIvar {
    Ivar ivar = class_getInstanceVariable(self.class, [@"_logic" UTF8String]);
    //参数:1.对象obj 2.实例变量ivar 3.实例变量的值id
    object_setIvar(self, ivar, @"123456");
}

#pragma mark - 获取对象中实例变量的值
- (void)lg_object_getIvar {
    Ivar ivar = class_getInstanceVariable(self.class, [@"_logic" UTF8String]);
    //参数:1.对象obj 2.实例变量ivar
    //返回:id
    NSString *result = object_getIvar(self, ivar);
    NSLog(@"lg_object_getIvar:%@",result);
}
#pragma mark - 实例化类
- (void)lg_class_createInstance {
    //参数:1.类Class 2.额外分配的字节数
    //返回:类的实例
    NSObject *result = class_createInstance([NSObject class], 0);
    NSLog(@"lg_class_createInstance:%@",result);
}

#pragma mark - 注册使用类
- (void)lg_objc_registerClassPair {
    Class result = objc_allocateClassPair([NSObject class], [@"NewClass" UTF8String], 0);
    //参数:类Class
    objc_registerClassPair(result);
}

#pragma mark - 销毁一个类
- (void)lg_objc_disposeClassPair {
    //参数:类Class
    Class result = objc_allocateClassPair([NSObject class], [@"NewClass" UTF8String], 0);
    objc_disposeClassPair(result);
}

#pragma mark - 添加一个新类
- (void)lg_objc_allocateClassPair {
    //参数:1.新添加类的父类 2.新类的名称 3.填0
    //返回:新类
    Class result = objc_allocateClassPair([NSObject class], [@"NewClass" UTF8String], 0);
    NSLog(@"lg_objc_allocateClassPair:%p",result);
}

#pragma mark - 设置类的版本号
- (void)lg_class_setVersion {
    //参数:1.类Class 2.int
    class_setVersion(self.class, 100);
}

#pragma mark - 获取类的版本号
- (void)lg_class_getVersion {
    //参数:类Class
    //返回:版本号
    int result = class_getVersion(self.class);
    NSLog(@"lg_class_getVersion:%d",result);
}

#pragma mark - 获取协议列表
- (void)lg_class_copyProtocolList {
    //入参:1、类Class 2、unsigned int 类型
    //返回:整个类的遵循的协议
    unsigned int copyProtocolListCount = 0;
    Protocol * __unsafe_unretained *protocals = class_copyProtocolList([self class], &copyProtocolListCount);
    for (NSInteger i = 0; i < copyProtocolListCount; i++) {
        Protocol * protocal = protocals[i];
        const char *name = protocol_getName(protocal);
        NSLog(@"lg_class_copyProtocolList:%s",name);
    }
    free(protocals);//释放
}

#pragma mark - 判断是否遵循某个协议
- (void)lg_class_conformsToProtocol {
    //参数:1.类Class 2.协议
    //返回:BOOL
    BOOL result = class_conformsToProtocol(self.class, NSProtocolFromString(@"UITableViewDelegate"));
    NSLog(@"lg_class_conformsToProtocol:%d",result);
}

#pragma mark - 替换类的属性
- (void)lg_class_replaceProperty {
    objc_property_attribute_t type = { "T", "@\"NSString\"" };
    objc_property_attribute_t ownership = { "C", "" }; // C = copy
    objc_property_attribute_t backingivar  = { "V", "_attribute0" };
    objc_property_attribute_t attrs[] = { type, ownership, backingivar };
    //参数:1.类Class 2.属性名称 3.属性的相关属性 4.属性的相关属性的个数
    class_replaceProperty(self.class, [@"logic" UTF8String], attrs, 3);
}

#pragma mark - 为类添加属性
//get方法
NSString *attribute0Getter(id classInstance, SEL _cmd) {
    Ivar ivar = class_getInstanceVariable([classInstance class], "_attribute0");//获取变量,如果没获取到说明不存在
    return object_getIvar(classInstance, ivar);
}
//set方法
void attribute0Setter(id classInstance, SEL _cmd, NSString *newName) {
    Ivar ivar = class_getInstanceVariable([classInstance class], "_attribute0");//获取变量,如果没获取到说明不存在
    id oldName = object_getIvar(classInstance, ivar);
    if (oldName != newName) object_setIvar(classInstance, ivar, [newName copy]);
}
- (void)lg_class_addProperty {
    objc_property_attribute_t type = { "T", "@\"NSString\"" };
    objc_property_attribute_t ownership = { "C", "" }; // C = copy
    objc_property_attribute_t backingivar  = { "V", "_attribute0" };
    objc_property_attribute_t attrs[] = { type, ownership, backingivar };
    //参数:1.类Class 2.属性数组 3.属性个数
    //返回值:BOOL
    BOOL suc0 = class_addProperty(self.class, "_attribute0", attrs, 3);
    
    SEL getter = NSSelectorFromString(@"attribute0");
    SEL setter = NSSelectorFromString(@"setAttribute0:");
    BOOL suc1 = class_addMethod(self.class, getter, (IMP)attribute0Getter, "@@:");
    BOOL suc2 = class_addMethod(self.class, setter, (IMP)attribute0Setter, "v@:@");
    NSLog(@"lg_class_addProperty:class_addProperty = %d,class_addMethod_Getter = %d,class_addMethod_Setter = %d",suc0,suc1,suc2);
}

#pragma mark - 添加协议
-(void)lg_class_addProtocol {
    //参数:1.类Class 2.协议
    //返回:BOOL
    BOOL result = class_addProtocol([self class], NSProtocolFromString(@"UITableViewDelegate"));
    NSLog(@"lg_class_addProtocol:%d",result);
}
#pragma mark - 判断是否响应方法
-(void)lg_class_respondsToSelector {
    //参数:1.类Class 2.方法名SEL
    //返回:BOOL
    BOOL result = class_respondsToSelector(self.class, @selector(viewDidLoad));
    NSLog(@"lg_class_respondsToSelector:%d",result);
}

#pragma mark - 获取方法实现
- (void)lg_class_getMethodImplementation {
    //参数:1.类Class 2.方法名SEL
    //返回:方法实现IMP
    IMP result = class_getMethodImplementation([ViewController class], @selector(lg_method));
    result();
}

- (void)lg_method {
    NSLog(@"lg_method lg_method lg_method");
}
#pragma mark - 交换方法
- (void)lg_class_replaceMethod {
    [self lg_method1];
    //参数:1.类Class 2.方法名SEL 3.方法的实现IMP 4.方法参数描述
    //返回:BOOL
    BOOL result = class_replaceMethod([self class], @selector(lg_method1), [self methodForSelector:@selector(lg_method2)], NULL);
    NSLog(@"lg_class_replaceMethod:%d",result);
    [self lg_method1];
}
- (void)lg_method1 {
    NSLog(@"lg_method1");
}
- (void)lg_method2 {
    NSLog(@"lg_method2");
}

#pragma mark - 获取整个类的实例方法
- (void)lg_class_copyMethodList {
    //参数:1、类Class 2、unsigned int 类型
    //返回:整个类的实例方法
    unsigned int copycopyMethodListCount = 0;
    Method *methods = class_copyMethodList([self class], &copycopyMethodListCount);
    for (NSInteger i = 0; i < copycopyMethodListCount; i++) {
        Method method = methods[i];
        SEL name = method_getName(method);
        NSLog(@"lg_class_copyMethodList:%@",NSStringFromSelector(name));
    }
    free(methods);//释放
}

#pragma mark - 获取类方法
- (void)lg_class_getClassMethod {
    //入参:1.类Class 2.方法名SEL
    //返回:method结构体指针
    Method result = class_getClassMethod(self.class, @selector(lgClassMethod));
    NSLog(@"lg_class_getClassMethod:%p",result);
}

+ (void)lgClassMethod {
    NSLog(@"我是类方法");
}

#pragma mark - 获取类的实例方法
- (void)lg_class_getInstanceMethod {
    //参数:1.类Class 2.方法名SEL
    //返回:method结构体指针
    Method result = class_getInstanceMethod(self.class, @selector(lg_method));
    NSLog(@"lg_class_getInstanceMethod:%p",result);
}
#pragma mark - 给类添加方法
- (void)lg_addMethod {
    //参数:1.类Class 2.方法名 3.imp,函数实现 4.方法参数类型描述
    //返回值:BOOL
    BOOL result = class_addMethod(self.class, NSSelectorFromString(@"lgMethod"), [self methodForSelector:@selector(lg_method)], "@@:");
    NSLog(@"lg_addMethod:%d",result);
}

#pragma mark - 获取整个属性列表
- (void)lg_class_copyPropertyList {
    //参数:1.类Class 2.unsigned int类型
    //返回:属性列表
    unsigned int copyPropertyListCount = 0;
    objc_property_t *propertys = class_copyPropertyList([self class], &copyPropertyListCount);
    for (NSInteger i = 0; i < copyPropertyListCount; i++) {
        objc_property_t property = propertys[i];
        const char *name = property_getName(property);
        NSLog(@"lg_class_copyPropertyList:%s",name);
    }
    free(propertys);//释放
}
#pragma mark - 获取指定的属性
- (void)lg_class_getProperty {
    //参数:1.类Class 2.属性名
    //返回:属性objc_property_t
    objc_property_t result = class_getProperty(self.class, [@"logic" UTF8String]);
    NSLog(@"lg_class_getProperty:%p",result);
}

#pragma mark - 获取类的weak修饰的实例变量
- (void)lg_class_getWeakIvarLayout {
    //参数:类Class
    //返回:返回值是指向 uint8_t 的指针
    const uint8_t *result = class_getWeakIvarLayout(self.class);
    NSLog(@"lg_class_getIvarLayout:%p",result);
}

#pragma mark - 设置类的实例变量的修饰符为weak
- (void)lg_class_setWeakIvarLayout{
    uint8_t u = 1;
    const uint8_t *u8  = &u;
    //参数:1.类Class 2.const uint8_t *
    class_setWeakIvarLayout(self.class, u8);
}

#pragma mark - 设置类的实例变量的修饰符
- (void)lg_class_setIvarLayout {
    uint8_t u = 1;
    const uint8_t *u8  = &u;
    //参数:1.类Class 2.const uint8_t *
    class_setIvarLayout(self.class, u8);
}

#pragma mark - 获取类的实例变量的修饰符
- (void)lg_class_getIvarLayout {
    //参数:类Class
    //返回:返回值是指向 uint8_t 的指针
    const uint8_t *result = class_getIvarLayout(self.class);
    NSLog(@"lg_class_getIvarLayout:%p",result);
}
#pragma mark - 获取整个成员变量列表
- (void)lg_class_copyIvarList {
    //入参:1、类Class 2、unsigned int类型
    //返回:Ivar 类型的指针数组
    unsigned int copyIvarListCount = 0;
    Ivar *ivars = class_copyIvarList([self class], &copyIvarListCount);
    for (NSInteger i = 0; i< copyIvarListCount; i ++) {
        Ivar ivar = ivars[i];
        const char *name = ivar_getName(ivar);
        NSLog(@"lg_class_copyIvarList:%s",name);
    }
    free(ivars);//释放
}

#pragma mark - 为动态创建的类添加变量
- (void)lg_class_addIvar {
    Class CreatClass0 = objc_allocateClassPair([NSObject class], "CreatClass0", 0);
    class_addIvar(CreatClass0, "_attribute0", sizeof(NSString *), log(sizeof(NSString *)), "i");
    Ivar ivar = class_getInstanceVariable(CreatClass0, "_attribute0");//获取变量,如果没获取到说明不存在
    NSLog(@"lg_class_addIvar:%@",[NSString stringWithUTF8String:ivar_getName(ivar)]);
    objc_registerClassPair(CreatClass0);
}
#pragma mark - 获取指定的类变量的信息的数据结构的指针
- (void)lg_class_getClassVariable {
    //参数:1.类Class 2.类变量名称
    //返回:指定的类变量的信息的数据结构的指针
    Ivar ivar = class_getClassVariable(self.class, [@"isa" UTF8String]);
    NSLog(@"lg_class_getClassVariable:%p",ivar);
}
#pragma mark - 判断类是否为元类
- (void)lg_class_isMetaClass {
    //参书:类Class
    //返回:BOOL类型
    BOOL result = class_isMetaClass([ViewController class]);
    NSLog(@"lg_class_isMetaClass:%d",result);
}
#pragma mark - 获取父类
- (void)lg_class_getSuperclass {
    //参数:类Class
    //返回:父类Class
    Class result = class_getSuperclass([ViewController class]);
    NSLog(@"lg_class_getName:%@",result);
}
#pragma mark - 获取类名
- (void)lg_class_getName {
    //参数:类Class
    //返回:类名char数组
    const char *result = class_getName([ViewController class]);
    NSLog(@"lg_class_getName:%@",[NSString stringWithUTF8String:result]);
}
#pragma mark - 获取实例大小
- (void)lg_class_getInstanceSize {
    //参数:类Class
    //返回:类的实例大小
    size_t result = class_getInstanceSize([ViewController class]);
    NSLog(@"lg_class_getInstanceSize:%zu",result);
}
#pragma mark - 获取类中指定的实例变量的信息的数据结构的指针
- (void)lg_class_getInstanceVariable {
    //参数:1.类Class 2.实例变量的名称
    //返回:Ivar指针
    const char *result1 = [@"_logic" UTF8String];
    Ivar result2 = class_getInstanceVariable([self class], result1);
    NSLog(@"lg_class_getInstanceVariable:%p",result2);
}

@end
